home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fsrecov / fsrecovStuff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  57.5 KB  |  2,003 lines

  1. /* 
  2.  * fsrecovStuff.c --
  3.  *
  4.  *    Fast recovery handling for the file system.
  5.  *
  6.  * Copyright 1991 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that this copyright
  10.  * notice appears in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fsrecov/fsrecovStuff.c,v 1.2 92/08/11 16:31:21 mgbaker Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <sprite.h>
  21. #include <fs.h>
  22. #include <fslcl.h>
  23. #include <fsio.h>
  24. #include <fsrecov.h>
  25. #include <fsdm.h>
  26. #include <recov.h>
  27. #include <fsutil.h>
  28. #include <stdio.h>
  29. #include <fspdev.h>
  30. #include <fsioDevice.h>
  31. #include <fsioPipe.h>
  32. #include <strings.h>
  33.  
  34. #define    FSRECOV_OBJECT_TYPE    0
  35.  
  36. DirEntryMap    fsrecov_DirLogObjNums[FSRECOV_NUM_DIR_LOG_ENTRIES];
  37. Boolean        finishedInit = FALSE;
  38. Fsrecov_DirLog    fsrecov_DirLog;
  39.  
  40. #define    FSRECOV_SAFE_SECONDS    60    /* After 35 seconds, a write should
  41.                      * be permanent.  This is safer. */
  42. int    fsrecov_MaxNumObjs = 0;
  43. static    Hash_Table    fsrecovHashTable;
  44.  
  45. Boolean    fsrecov_AlreadyInit = FALSE;    /* Recov box existed on reboot. */
  46. Boolean    fsrecov_FromBox = TRUE;        /* Do the recovery from what we
  47.                      * have in the recov box, even for
  48.                      * old clients that are doing
  49.                      * reopens. */
  50. int    fsrecov_DebugLevel = 1;        /* 0 == off.  2 == everything. */
  51.  
  52. /*
  53.  * Stuff for doing testing and timing.
  54.  */
  55. Time    fsrecov_StartRebuild;
  56. Time    fsrecov_ReturnedObjs;
  57. Time    fsrecov_BuiltHashTable;
  58. Time    fsrecov_BuiltIOHandles;
  59. Time    fsrecov_EndRebuild;
  60. int     fsrecov_RebuildNumObjs;
  61.  
  62. typedef    struct ClientObject {
  63.     int            objectNumber;
  64.     Fsio_UseCounts    use;
  65. } ClientObject;
  66.  
  67. char    *LogOpString _ARGS_((int op));
  68.  
  69. Boolean    logProcessDebug = TRUE;
  70.  
  71. #define    CHECK        /* Check against stored objects. */
  72.  
  73.  
  74. /*
  75.  *----------------------------------------------------------------------
  76.  *
  77.  * Fsrecov_InitState --
  78.  *
  79.  *    Initialize recov state in recov box for file system.
  80.  *
  81.  * Results:
  82.  *    None.
  83.  *
  84.  * Side effects:
  85.  *    Recov box gets initialized if it wasn't already.  Hash table of
  86.  *    mappings from fileID to object number gets created but not set up.
  87.  *
  88.  *----------------------------------------------------------------------
  89.  */
  90. void
  91. Fsrecov_InitState()
  92. {
  93.     ReturnStatus        status;
  94.     int                objectType;
  95.     int                numDirLogsPerHandle;
  96.     int                numMarksObjsPerHandle;
  97. #define    NUM_MARKS_OBJS        100
  98. #define    SIZE_MARKS_OBJS        500
  99.  
  100.     /*
  101.      * Initialize the recovery module.  Do before Rpc and after Vm_Init.
  102.      *
  103.      * If this is a fastRestart, then the recov box will already have
  104.      * been initialized with our fs object type.
  105.      */
  106.     fsrecov_AlreadyInit = Recov_InitRecovBox();
  107.     fsrecov_MaxNumObjs = Recov_MaxNumObjects(sizeof (Fsrecov_HandleState),
  108.         fsrecov_AlreadyInit);
  109.     /* Allow some room for other objects to use the box. */
  110.     if (sizeof (Fsrecov_DirLogEntry) > sizeof (Fsrecov_HandleState)) {
  111.     numDirLogsPerHandle = (sizeof (Fsrecov_DirLogEntry) /
  112.         sizeof (Fsrecov_HandleState)) + 1;
  113.     } else {
  114.     numDirLogsPerHandle = 1;
  115.     }
  116.     if (SIZE_MARKS_OBJS > sizeof (Fsrecov_HandleState)) {
  117.     numMarksObjsPerHandle = (SIZE_MARKS_OBJS /
  118.         sizeof (Fsrecov_HandleState)) + 1;
  119.     } else {
  120.     numMarksObjsPerHandle = 1;
  121.     }
  122.     if (fsrecov_MaxNumObjs >
  123.         (100 + (FSRECOV_NUM_DIR_LOG_ENTRIES * numDirLogsPerHandle) +
  124.         (NUM_MARKS_OBJS * numMarksObjsPerHandle))) {
  125.     fsrecov_MaxNumObjs -= 100 +
  126.         (FSRECOV_NUM_DIR_LOG_ENTRIES * numDirLogsPerHandle) +
  127.         (NUM_MARKS_OBJS * numMarksObjsPerHandle);
  128.     }
  129.     Hash_Init(&fsrecovHashTable, 8, sizeof (Fs_FileID) / sizeof (int));
  130.     if (!fsrecov_AlreadyInit) {
  131.     status = Recov_InitType(sizeof (Fsrecov_HandleState),
  132.         fsrecov_MaxNumObjs, 0, &objectType, Fsrecov_Checksum);
  133.     if (status != SUCCESS) {
  134.         panic("Fs_InitRecovState: couldn't initialize object type.");
  135.     }
  136.     if (objectType != FSRECOV_OBJECT_TYPE) {
  137.         panic("Fs_InitRecovState: somebody else got here first.");
  138.     }
  139.     }
  140.     return;
  141. }
  142.     
  143.  
  144. /*
  145.  *----------------------------------------------------------------------
  146.  *
  147.  * Fsrecov_SetupHandles --
  148.  *
  149.  *    Use the handle state from the recov box to set up stuff.
  150.  *
  151.  * Results:
  152.  *    None.
  153.  *
  154.  * Side effects:
  155.  *    Hash table of mappings from fileID to object number gets set up
  156.  *    (and filled in if this is a fast restart).
  157.  *
  158.  *----------------------------------------------------------------------
  159.  */
  160. void
  161. Fsrecov_SetupHandles()
  162. {
  163.     ReturnStatus        status;
  164.     Fsrecov_HandleState        *obuffer;
  165.     int                osizeNeeded;
  166.     Recov_ObjectID        *ibuffer;
  167.     int                isizeNeeded;
  168.     Hash_Entry            *entryPtr;
  169.     int                i;
  170.     Fs_FileID            fileID;
  171.     Recov_ObjectID        objID;
  172.     Fsrecov_HandleState        *recovInfoPtr;
  173.  
  174.     if (!fsrecov_AlreadyInit) {
  175.     return;
  176.     }
  177.     Timer_GetTimeOfDay(&fsrecov_StartRebuild, (int *) NIL, (Boolean *) NIL);
  178.     /*
  179.      * Set-up handle table from what's in box.
  180.      */
  181.     osizeNeeded = sizeof (Fsrecov_HandleState) * fsrecov_MaxNumObjs;
  182.     obuffer = (Fsrecov_HandleState *) malloc(osizeNeeded);
  183.     if (obuffer == (Fsrecov_HandleState *) NIL) {
  184.     panic("Fsrecov_SetupHandles: not enough object buffer space.");
  185.     }
  186.     isizeNeeded = sizeof (Recov_ObjectID) * fsrecov_MaxNumObjs;
  187.     ibuffer = (Recov_ObjectID *) malloc(isizeNeeded);
  188.     if (ibuffer == (Recov_ObjectID *) NIL) {
  189.     free((char *) obuffer);
  190.     panic("Fsrecov_SetupHandles: not enough object buffer space.");
  191.     }
  192.     status = Recov_ReturnObjects(FSRECOV_OBJECT_TYPE, &osizeNeeded,
  193.         (char *) obuffer, &isizeNeeded, (char *) ibuffer, (int *) NIL,
  194.         (char *) NIL);
  195.     if (status != SUCCESS) {
  196.     free((char *) obuffer);
  197.     free((char *) ibuffer);
  198.     panic("Fsrecov_SetupHandles: couldn't get old object list out of box.");
  199.     }
  200.     fsrecov_RebuildNumObjs = osizeNeeded / sizeof (Fsrecov_HandleState);
  201.     Timer_GetTimeOfDay(&fsrecov_ReturnedObjs, (int *) NIL, (Boolean *) NIL);
  202.     /*
  203.      * Put mapping from fileID (with clientID as first field) to object
  204.      * number into hash table.
  205.      */
  206.     for (i = 0; i < fsrecov_RebuildNumObjs; i++) {
  207.     /* This is a fileID, but with the first field being the clientID. */
  208.     fileID = obuffer[i].fileID;
  209.     objID = ibuffer[i];
  210.     /* Put objectID/fileID pairing in hash table. */
  211.     entryPtr = Hash_Find(&fsrecovHashTable, (Address) &fileID);
  212.     if (entryPtr->value != (Address) NIL) {
  213.         free((char *) obuffer);
  214.         free((char *) ibuffer);
  215.         panic("Fsrecov_SetupHandles: file ID already in table for client.");
  216.     }
  217.     entryPtr->value = (Address) malloc(sizeof (ClientObject));
  218.     ((ClientObject *) entryPtr->value)->objectNumber =
  219.         ibuffer[i].objectNumber;
  220.     ((ClientObject *) entryPtr->value)->use = obuffer[i].use;
  221.     }
  222.  
  223.     /*
  224.      * If we're not really to use the stuff from the recov box to recover
  225.      * our state, then just return here before we do that.
  226.      */
  227.     if (!fsrecov_FromBox) {
  228.     return;
  229.     }
  230.  
  231.     /*
  232.      * Now that we have the hash table so that we can find the objects
  233.      * for any file ID, go through and set up the client lists and initialize
  234.      * the io handles.
  235.      */
  236.     Timer_GetTimeOfDay(&fsrecov_BuiltHashTable, (int *) NIL, (Boolean *) NIL);
  237.     for (i = 0; i < fsrecov_RebuildNumObjs; i++) {
  238.     fileID = obuffer[i].fileID;
  239.     recovInfoPtr = &obuffer[i];
  240.  
  241.     switch(fileID.type) {
  242.     case FSIO_LCL_FILE_STREAM:
  243.     case FSIO_RMT_FILE_STREAM: {
  244.         (void) Fsio_FileSetupHandle(recovInfoPtr);
  245.         break;
  246.     }
  247.     case FSIO_LCL_DEVICE_STREAM:
  248.     case FSIO_RMT_DEVICE_STREAM: {
  249.         (void) Fsio_DeviceSetupHandle(recovInfoPtr);
  250.         break;
  251.     }
  252.     case FSIO_LCL_PIPE_STREAM:
  253.     case FSIO_RMT_PIPE_STREAM: {
  254.         (void) Fsio_PipeSetupHandle(recovInfoPtr);
  255.         break;
  256.     }
  257.     case FSIO_CONTROL_STREAM:
  258.     case FSIO_PFS_CONTROL_STREAM: {
  259.         (void) Fspdev_ControlSetupHandle(recovInfoPtr);
  260.         break;
  261.     }
  262.     default:
  263.         break;
  264.     }
  265.     }
  266.     Timer_GetTimeOfDay(&fsrecov_BuiltIOHandles, (int *) NIL, (Boolean *) NIL);
  267.     /*
  268.      * Finally, reopen all the streams.
  269.      */
  270.     for (i = 0; i < fsrecov_RebuildNumObjs; i++) {
  271.     fileID = obuffer[i].fileID;
  272.     if (fileID.type == FSIO_STREAM) {
  273.         Fs_HandleHeader    *ioHandlePtr;
  274.         int            clientID;
  275.         Fs_HandleHeader    handle;
  276.         Fs_FileID        otherID;
  277.         Fs_Stream        *streamPtr;
  278.  
  279.         objID = ibuffer[i];
  280.         recovInfoPtr = &obuffer[i];
  281.         otherID = recovInfoPtr->otherID;
  282.  
  283.         /* Fix ID's to include correct serverID. */
  284.         clientID = fileID.serverID;
  285.         otherID.serverID = rpc_SpriteID;
  286.         fileID.serverID = rpc_SpriteID;
  287.         handle.fileID = fileID;
  288.         /*
  289.          * The client verify that's done in the real stream reopen
  290.          * does a verify on the remote handle type, since it hasn't
  291.          * converted the type yet.  Then it turns around and converts
  292.          * the type to be local.  Here, it just ends up re-localizing
  293.          * a type that's already local.
  294.          */
  295.         ioHandlePtr = (*fsio_StreamOpTable[
  296.             Fsio_MapLclToRmtType(otherID.type)].clientVerify)
  297.             (&otherID, clientID, (int *) NIL);
  298.         if (ioHandlePtr == (Fs_HandleHeader *) NIL) {
  299.         panic("Fsrecov_SetupHandles: no handle found for stream.\n");
  300.         /*
  301.          * The info field of the object data for a stream includes
  302.          * its flags to pass to the delete routine.
  303.          */
  304.         if (Fsrecov_DeleteHandle(&handle, clientID, recovInfoPtr->info)
  305.             != SUCCESS) {
  306.             printf(
  307.             "Fsrecov_SetupHandles: couldn't delete bad stream.\n");
  308.         }
  309.         continue;
  310.         }
  311.         streamPtr = Fsutil_HandleFetchType(Fs_Stream, &fileID);
  312.         /* This should usually return NIL. */
  313.         if (streamPtr != (Fs_Stream *) NIL) {
  314.         /* Verify we have the stream hooked to the correct ioHandle. */
  315.         if (streamPtr->ioHandlePtr != ioHandlePtr) {
  316.             printf(
  317.             "Fsrecov_SetupHandles: bad handle found for stream.\n");
  318.             if (Fsrecov_DeleteHandle(&handle, clientID,
  319.                 recovInfoPtr->info) != SUCCESS) {
  320.             printf(
  321.             "Fsrecov_SetupHandles: couldn't delete bad stream.\n");
  322.             }
  323.             Fsutil_HandleRelease(streamPtr, TRUE);
  324.             Fsutil_HandleRelease(ioHandlePtr, TRUE);
  325.             continue;
  326.         } else {
  327.             Fsutil_HandleRelease(streamPtr, TRUE);
  328.         }
  329.         /* Check sharing stuff done in Fsio_StreamReopen? */
  330.         }
  331.         /* streamPtr->flags set from recovInfoPtr->info parameter. */
  332.         streamPtr = Fsio_StreamAddClient(&fileID, clientID, ioHandlePtr,
  333.             recovInfoPtr->info, ioHandlePtr->name, (Boolean *) NIL,
  334.             (Boolean *) NIL);
  335.         streamPtr->offset = recovInfoPtr->clientData;
  336.         Fsutil_HandleRelease(streamPtr, TRUE);
  337.         Fsutil_HandleRelease(ioHandlePtr, TRUE);
  338.     }
  339.     }
  340.     Timer_GetTimeOfDay(&fsrecov_EndRebuild, (int *) NIL, (Boolean *) NIL);
  341.  
  342.     free((char *) obuffer);
  343.     free((char *) ibuffer);
  344.  
  345.     return;
  346. }
  347.  
  348. /*
  349.  *----------------------------------------------------------------------
  350.  *
  351.  * Fsrecov_AddHandle --
  352.  *
  353.  *    Add a handle to the recov state in recov box for file system.
  354.  *
  355.  * Results:
  356.  *    SUCCESS or FAILURE.
  357.  *
  358.  * Side effects:
  359.  *    
  360.  *    Add a handle to the recov box and its fileID/objectID mapping
  361.  *    to the hash table.
  362.  *
  363.  *----------------------------------------------------------------------
  364.  */
  365. ReturnStatus
  366. Fsrecov_AddHandle(hdrPtr, otherIDPtr, clientID, useFlags, clientData, addRef)
  367.     Fs_HandleHeader        *hdrPtr;
  368.     Fs_FileID            *otherIDPtr;
  369.     int                clientID;
  370.     unsigned int        useFlags;
  371.     int                clientData;
  372.     Boolean            addRef;
  373. {
  374.     int                status = SUCCESS;
  375.     Recov_ObjectID        objectID;
  376.     Fsrecov_HandleState        objectData;
  377.     Hash_Entry            *entryPtr;
  378.  
  379.     /* Add objectID/fileID mapping to hash table. */
  380.     objectData.fileID = hdrPtr->fileID;
  381.     objectData.fileID.serverID = clientID;
  382.     if (fsrecov_DebugLevel >= 3) {
  383.     printf("Fs_Add: looking for %d.%d.%d.%d\n", objectData.fileID.type,
  384.     objectData.fileID.serverID, objectData.fileID.major,
  385.     objectData.fileID.minor);
  386.     }
  387.     entryPtr = Hash_Find(&fsrecovHashTable, (Address) &objectData.fileID);
  388.     if (entryPtr->value != (Address) NIL) {
  389.     if (fsrecov_DebugLevel >= 3) {
  390.         printf("Found.\n");
  391.     }
  392.     /* Already a handle for this client/file pair. */
  393.     objectID.typeID = FSRECOV_OBJECT_TYPE;
  394.     objectID.objectNumber =
  395.         ((ClientObject *) entryPtr->value)->objectNumber;
  396.     objectData.use =
  397.         ((ClientObject *) entryPtr->value)->use;
  398. #ifdef CHECK
  399.     status = Recov_ReturnObject((ClientData) &objectData, objectID, FALSE);
  400.     if (status != SUCCESS) {
  401.         panic("Fsrecov_AddHandle: couldn't find existing object in box.");
  402.     }
  403. #endif CHECK
  404.     /* Increment ref counts for this client's use of file. */
  405.     if (addRef) {
  406.         objectData.use.ref++;
  407.         if (hdrPtr->fileID.type != FSIO_CONTROL_STREAM &&
  408.             hdrPtr->fileID.type != FSIO_PFS_CONTROL_STREAM) {
  409.         if (useFlags & FS_WRITE) {
  410.             objectData.use.write++;
  411.         }
  412.         if (useFlags & FS_EXECUTE) {
  413.             objectData.use.exec++;
  414.         }
  415.         }
  416.         ((ClientObject *) entryPtr->value)->use = objectData.use;
  417.     }
  418.     objectData.otherID.type = -1;
  419.     objectData.otherID.serverID = -1;
  420.     objectData.otherID.major = -1;
  421.     objectData.otherID.minor = -1;
  422.     /* Check other state. */
  423.     if (hdrPtr->fileID.type == FSIO_LCL_FILE_STREAM) {
  424.         Fsio_FileIOHandle        *handlePtr;
  425.         
  426.         handlePtr = (Fsio_FileIOHandle *) hdrPtr;
  427. #ifdef CHECK
  428.         /* Info is file version. */
  429.         if (objectData.info != handlePtr->descPtr->version) {
  430.         if (fsrecov_DebugLevel >= 2) {
  431.             printf(
  432.             "Fsrecov_AddHandle: changing version number of object.\n");
  433.         }
  434.         objectData.info = handlePtr->descPtr->version;
  435.         }
  436. #else CHECK
  437.         objectData.info = handlePtr->descPtr->version;
  438. #endif CHECK
  439.  
  440. #ifdef CHECK
  441.         /* ClientData is whether file is cacheable or not. */
  442.         if (objectData.clientData != clientData) {
  443.         printf(
  444.             "Fsrecov_AddHandle: changing cachable state of object.\n");
  445.         objectData.clientData = clientData;
  446.         }
  447. #else CHECK
  448.         objectData.clientData = clientData;
  449. #endif CHECK
  450.     } else if (hdrPtr->fileID.type == FSIO_CONTROL_STREAM ||
  451.         hdrPtr->fileID.type == FSIO_PFS_CONTROL_STREAM) {
  452.         /* Info is the serverID == hostID of machine running the server. */
  453.         objectData.info = clientID;
  454.         /* ClientData is the "seed." */
  455.         objectData.clientData = clientData;
  456.         /* The useFlags may indicate NIL serverID. */
  457.         if (useFlags == NIL) {
  458.         objectData.info = NIL;
  459.         }
  460.     } else if (hdrPtr->fileID.type == FSIO_STREAM) {
  461.         if (otherIDPtr != (Fs_FileID *) NIL) {
  462.         objectData.otherID = *otherIDPtr;
  463.         }
  464.         /* ClientData is stream offset. */
  465.         objectData.clientData = clientData;
  466.         /* Info is useFlags since there's other fields that count there. */
  467.         objectData.info = useFlags;
  468.     }
  469.  
  470.     /* Update object in box. */
  471.     status = Recov_UpdateObject((ClientData ) &objectData, objectID);
  472.     if (status != SUCCESS) {
  473.         panic("Fsrecov_AddHandle: couldn't update object in box.");
  474.     }
  475.     } else {
  476.     if (fsrecov_DebugLevel >= 3) {
  477.         printf("NOT found.\n");
  478.     }
  479.     /* Put the file into the box for the first time for this client. */
  480.     if (addRef) {
  481.         objectData.use.ref = 1;
  482.     } else {
  483.         objectData.use.ref = 0;
  484.     }
  485.     objectData.use.write = 0;
  486.     objectData.use.exec = 0;
  487.     if (addRef) {
  488.         if (hdrPtr->fileID.type != FSIO_CONTROL_STREAM &&
  489.             hdrPtr->fileID.type != FSIO_PFS_CONTROL_STREAM) {
  490.         if (useFlags & FS_WRITE) {
  491.             objectData.use.write = 1;
  492.         }
  493.         if (useFlags & FS_EXECUTE) {
  494.             objectData.use.exec = 1;
  495.         }
  496.         }
  497.     }
  498.     objectData.otherID.type = -1;
  499.     objectData.otherID.serverID = -1;
  500.     objectData.otherID.major = -1;
  501.     objectData.otherID.minor = -1;
  502.     if (hdrPtr->fileID.type == FSIO_LCL_FILE_STREAM) {
  503.         Fsio_FileIOHandle        *handlePtr;
  504.         
  505.         handlePtr = (Fsio_FileIOHandle *) hdrPtr;
  506.         /* Info is file version. */
  507.         objectData.info = handlePtr->descPtr->version;
  508.         /* ClientData is whether file is cacheable or not. */
  509.         objectData.clientData = clientData;
  510.     } else if (hdrPtr->fileID.type == FSIO_CONTROL_STREAM ||
  511.         hdrPtr->fileID.type == FSIO_PFS_CONTROL_STREAM) {
  512.         /* Info is the serverID == hostID of machine running the server. */
  513.         objectData.info = clientID;
  514.         /* ClientData is the "seed." */
  515.         objectData.clientData = clientData;
  516.         /* The useFlags may indicate NIL serverID. */
  517.         if (useFlags == NIL) {
  518.         objectData.info = NIL;
  519.         }
  520.     } else if (hdrPtr->fileID.type == FSIO_STREAM) {
  521.         if (otherIDPtr != (Fs_FileID *) NIL) {
  522.         objectData.otherID = *otherIDPtr;
  523.         }
  524.         /* ClientData is offset of stream. */
  525.         objectData.clientData = clientData;
  526.         /* Info is useFlags since there's other fields that count there. */
  527.         objectData.info = useFlags;
  528.     } else {
  529.         objectData.clientData = 0;
  530.         objectData.info = 0;
  531.     }
  532.     status = Recov_InsertObject(FSRECOV_OBJECT_TYPE,
  533.         (ClientData) &objectData, -1, &objectID);
  534.     if (status != SUCCESS) {
  535.         printf("Fsrecov_AddHandle: object insert failed.\n");
  536.     }
  537.     entryPtr->value = (Address) malloc(sizeof (ClientObject));
  538.     ((ClientObject *) entryPtr->value)->objectNumber =
  539.         objectID.objectNumber;
  540.     ((ClientObject *) entryPtr->value)->use = objectData.use;
  541.     }
  542.  
  543.     return status;
  544. }
  545.  
  546. /*
  547.  *----------------------------------------------------------------------
  548.  *
  549.  * Fsrecov_DeleteHandle --
  550.  *
  551.  *    Delete a handle in the recov state in recov box for file system.
  552.  *
  553.  * Results:
  554.  *    SUCCESS or FAILURE.
  555.  *
  556.  * Side effects:
  557.  *    
  558.  *    Delete a file handle in the recov box and its fileID/objectID mapping
  559.  *    to the hash table.
  560.  *
  561.  *----------------------------------------------------------------------
  562.  */
  563. ReturnStatus
  564. Fsrecov_DeleteHandle(hdrPtr, clientID, flags)
  565.     Fs_HandleHeader        *hdrPtr;
  566.     int                clientID;
  567.     unsigned int        flags;
  568. {
  569.     int                status;
  570.     Recov_ObjectID        objectID;
  571.     Fsrecov_HandleState        objectData;
  572.     Hash_Entry            *entryPtr;
  573.  
  574.     /*
  575.      * If we decide ever to make stuff recacheable after an offender closes
  576.      * a file, I'd have to pass in that info and deal with it here.
  577.      */
  578.  
  579.     /* Get objectID/fileID mapping to hash table. */
  580.     objectData.fileID = hdrPtr->fileID;
  581.     objectData.fileID.serverID = clientID;
  582.     if (fsrecov_DebugLevel >= 3) {
  583.     printf("Fs_Delete: looking for %d.%d.%d.%d\n", objectData.fileID.type,
  584.     objectData.fileID.serverID, objectData.fileID.major,
  585.     objectData.fileID.minor);
  586.     }
  587.     entryPtr = Hash_Find(&fsrecovHashTable, (Address) &objectData.fileID);
  588.     if (entryPtr->value == (Address) NIL) {
  589.     /* No handle for this client/file pair! */
  590.     panic("Fsrecov_DeleteHandle: couldn't find object in hash table.");
  591.     }
  592.     if (fsrecov_DebugLevel >= 3) {
  593.     printf("Found.\n");
  594.     }
  595.     objectID.typeID = FSRECOV_OBJECT_TYPE;
  596.     objectID.objectNumber = ((ClientObject *) entryPtr->value)->objectNumber;
  597.  
  598.     objectData.otherID.type = -1;
  599.     objectData.otherID.serverID = -1;
  600.     objectData.otherID.major = -1;
  601.     objectData.otherID.minor = -1;
  602. #ifdef CHECK
  603.     status = Recov_ReturnObject((ClientData) &objectData, objectID, FALSE);
  604.     if (status != SUCCESS) {
  605.     panic("Fsrecov_DeleteHandle: couldn't return object.");
  606.     }
  607. #else CHECK
  608.     objectData.use = ((ClientObject *) entryPtr->value)->use;
  609. #endif CHECK
  610.  
  611.     objectData.use.ref--;
  612.     if (flags & FS_EXECUTE) {
  613.     objectData.use.exec--;
  614.     }
  615.     if (flags & FS_WRITE) {
  616.     objectData.use.write--;
  617.     }
  618.     if (fsrecov_DebugLevel >= 3) {
  619.     printf("Ref is %d\n", objectData.use.ref);
  620.     }
  621.  
  622.     if (fsrecov_DebugLevel >= 3) {
  623.     if (objectData.use.ref < 0) {
  624.         printf("Ref count is %d\n", objectData.use.ref);
  625.     }
  626.     }
  627.  
  628.     /*
  629.      * If the reference count has gone to 0 and there are no dirty
  630.      * blocks in the client's cache to be written back, then we can
  631.      * delete the last reference to this handle in the recovery box.
  632.      * This is true also if the file is not cacheable, since there'll be
  633.      * no dirty blocks in that case.
  634.      * Otherwise, we can only decrement the reference counts.
  635.      * This means it's possible for a handle to be in the recovery box
  636.      * with a 0 reference count if it still has dirty blocks to write back.
  637.      */
  638.     if (objectData.use.ref <= 0 &&
  639.         ((hdrPtr->fileID.type != FSIO_LCL_FILE_STREAM &&
  640.         hdrPtr->fileID.type != FSIO_RMT_FILE_STREAM) ||
  641.         (flags & FS_LAST_DIRTY_BLOCK) || (objectData.clientData == 0))) {
  642.     /* Delete the object. */
  643.     if (fsrecov_DebugLevel >= 3) {
  644.         printf("Deleting object.\n");
  645.         if (flags & FS_LAST_DIRTY_BLOCK) {
  646.         printf("Was last dirty block.\n");
  647.         }
  648.     }
  649.     status = Recov_DeleteObject(objectID);
  650.     if (status != SUCCESS) {
  651.         panic("Fsrecov_DeleteHandle: Couldn't delete existing object.");
  652.     }
  653.     /* Also delete from hash table. */
  654.     free(entryPtr->value);
  655.     Hash_Delete(&fsrecovHashTable, entryPtr);
  656.     } else {
  657. #ifndef CHECK
  658.     if (hdrPtr->fileID.type == FSIO_STREAM) {
  659.         Fs_Stream    *streamPtr;
  660.  
  661.         streamPtr = (Fs_Stream *) hdrPtr;
  662.         if (streamPtr->ioHandlePtr == (Fs_HandleHeader *) NIL) {
  663.         panic("Fsrecov_DeleteHandle: NIL ioHandlePtr.");
  664.         }
  665.         objectData.otherID = streamPtr->ioHandlePtr->hdr;
  666.  
  667.         /* ClientData is stream offset. */
  668.         objectData.clientData = streamPtr->offset;
  669.         /* Info is useFlags. */
  670.         objectData.info = streamPtr->flags;
  671.     }
  672.     if (hdrPtr->fileID.type == FSIO_CONTROL_STREAM ||
  673.         hdrPtr->fileID.type == FSIO_PFS_CONTROL_STREAM) {
  674.         /* Make this easy for now, if slower for pseudo devices. */
  675.         status = Recov_ReturnObject((ClientData) &objectData, objectID,
  676.             FALSE);
  677.         if (status != SUCCESS) {
  678.         panic("Fsrecov_DeleteHandle: couldn't return pseudo device.");
  679.         }
  680.         /* Info is the serverID == hostID of machine running the server. */
  681.         /* ClientData is the "seed." */
  682.         /* useFlags may indicate NIL serverID. */
  683.     }
  684.     if (hdrPtr->fileID.type == FSIO_LCL_FILE_STREAM) {
  685.         Fsio_FileIOHandle    *handlePtr;
  686.  
  687.         handlePtr = (Fsio_FileIOHandle *) hdrPtr;
  688.         /* ClientData is whether file is cacheable or not. */
  689.         fileStatePtr->cacheable
  690.         /* Info is file version. */
  691.         objectData.info = handlePtr->descPtr->version;
  692.     }
  693. #endif CHECK
  694.     /* Update the object with new ref counts. */
  695.     status = Recov_UpdateObject((ClientData ) &objectData, objectID);
  696.     if (status != SUCCESS) {
  697.         panic("Fsrecov_DeleteHandle: couldn't update object in box.");
  698.     }
  699.     ((ClientObject *) entryPtr->value)->use = objectData.use;
  700.     }
  701.         
  702.     return status;
  703. }
  704.  
  705. /*
  706.  *----------------------------------------------------------------------
  707.  *
  708.  * Fsrecov_GetHandle --
  709.  *
  710.  *    Return a handle from the recov state in recov box for file system.
  711.  *
  712.  * Results:
  713.  *    SUCCESS or FAILURE.
  714.  *
  715.  * Side effects:
  716.  *    
  717.  *    Return an object filled in with the recovery box entry.
  718.  *
  719.  *----------------------------------------------------------------------
  720.  */
  721. ReturnStatus
  722. Fsrecov_GetHandle(fileID, clientID, objectPtr, checksum)
  723.     Fs_FileID        fileID;
  724.     int            clientID;
  725.     Fsrecov_HandleState    *objectPtr;
  726.     Boolean        checksum;
  727. {
  728.     Hash_Entry            *entryPtr;
  729.     Recov_ObjectID        objectID;
  730.     ReturnStatus        status = SUCCESS;
  731.     
  732.     /* Get objectID/fileID mapping to hash table. */
  733.     fileID.serverID = clientID;
  734.     if (fsrecov_DebugLevel >= 3) {
  735.     printf("Fs_Get: looking for %d.%d.%d.%d\n",
  736.         fileID.type, fileID.serverID,
  737.         fileID.major, fileID.minor);
  738.     }
  739.     entryPtr = Hash_Find(&fsrecovHashTable, (Address) &fileID);
  740.     if (entryPtr->value == (Address) NIL) {
  741.     /* No handle for this client/file pair! */
  742.     return FAILURE;
  743.     }
  744.     objectID.typeID = FSRECOV_OBJECT_TYPE;
  745.     objectID.objectNumber = ((ClientObject *) entryPtr->value)->objectNumber;
  746.     status = Recov_ReturnObject((ClientData) objectPtr, objectID, checksum);
  747.  
  748.     return status;
  749. }
  750.  
  751. /*
  752.  *----------------------------------------------------------------------
  753.  *
  754.  * Fsrecov_UpdateHandle --
  755.  *
  756.  *    Update a handle in the recov state in recov box for file system.
  757.  *
  758.  * Results:
  759.  *    SUCCESS or FAILURE.
  760.  *
  761.  * Side effects:
  762.  *    
  763.  *    Updates the information for a handle in the recov box.
  764.  *
  765.  *----------------------------------------------------------------------
  766.  */
  767. ReturnStatus
  768. Fsrecov_UpdateHandle(fileID, clientID, objectPtr)
  769.     Fs_FileID        fileID;
  770.     int            clientID;
  771.     Fsrecov_HandleState    *objectPtr;
  772. {
  773.     Hash_Entry            *entryPtr;
  774.     Recov_ObjectID        objectID;
  775.     ReturnStatus        status;
  776.     
  777.     /* Get objectID/fileID mapping to hash table. */
  778.     fileID.serverID = clientID;
  779.     if (fsrecov_DebugLevel >= 3) {
  780.     printf("Fs_Get: looking for %d.%d.%d.%d\n", fileID.type,
  781.         fileID.serverID, fileID.major, fileID.minor);
  782.     }
  783.     entryPtr = Hash_Find(&fsrecovHashTable, (Address) &fileID);
  784.     if (entryPtr->value == (Address) NIL) {
  785.     /* No handle for this client/file pair! */
  786.     panic("Fsrecov_UpdateHandle: couldn't find object in hash table.");
  787.     }
  788.     objectID.typeID = FSRECOV_OBJECT_TYPE;
  789.     objectID.objectNumber = ((ClientObject *) entryPtr->value)->objectNumber;
  790.     status = Recov_UpdateObject((ClientData) objectPtr, objectID);
  791.     /* We'll need to do better than this! */
  792.     if (status != SUCCESS) {
  793.     panic("Fsrecov_UpdateHandle: couldn't get object.");
  794.     }
  795.     return SUCCESS;
  796. }
  797.  
  798.  
  799. /*
  800.  *----------------------------------------------------------------------
  801.  *
  802.  * Fsrecov_ThisType --
  803.  *
  804.  *    Is this the type of handle to put in the recov box?
  805.  *
  806.  * Results:
  807.  *    TRUE or FALSE (yes or no).
  808.  *
  809.  * Side effects:
  810.  *    
  811.  *    None.
  812.  *
  813.  *----------------------------------------------------------------------
  814.  */
  815. Boolean
  816. Fsrecov_ThisType(hdrPtr, clientID)
  817.     Fs_HandleHeader    *hdrPtr;
  818.     int            clientID;
  819. {
  820.     Boolean    saveThis = FALSE;
  821.  
  822.     switch (hdrPtr->fileID.type) {
  823.     case FSIO_LCL_FILE_STREAM:
  824.     case FSIO_RMT_FILE_STREAM: {
  825.     if (clientID != rpc_SpriteID) {
  826.         saveThis = TRUE;
  827.     }
  828.     break;
  829.     }
  830.     case FSIO_LCL_DEVICE_STREAM:
  831.     case FSIO_RMT_DEVICE_STREAM: {
  832.     if (clientID != rpc_SpriteID) {
  833.         saveThis = TRUE;
  834.     }
  835.     break;
  836.     }
  837.     case FSIO_CONTROL_STREAM: {
  838.     /*
  839.      * Save the control handle if the pdev server is not us: the serverID
  840.      * will either be NIL or something that's not our rpc_SpriteID.  Why
  841.      * am I checking the clientID also?  I don't know...  It should
  842.      * usually be the same as the server ID unless that's NIL.
  843.      */
  844.     if (clientID != rpc_SpriteID &&
  845.         ((Fspdev_ControlIOHandle *) hdrPtr)->serverID != rpc_SpriteID) {
  846.         saveThis = TRUE;
  847.     }
  848.     break;
  849.     }
  850.     default:
  851.     break;
  852.     }
  853.  
  854.     return saveThis;
  855. }
  856.  
  857.  
  858. /*
  859.  *----------------------------------------------------------------------
  860.  *
  861.  * Fsrecov_Checksum --
  862.  *
  863.  *    Compute the 16-bit one's complement of the 1's complement sum of
  864.  *    of all words in the buffer, which is an Fsrecov_HandleState item.
  865.  *
  866.  *    Note: It is assumed that the length of the buffer is at most
  867.  *    128K bytes long. It also helps if the buffer is word-aligned.
  868.  *
  869.  * Results:
  870.  *    The 1's complement checksum in network byte-order.
  871.  *
  872.  * Side effects:
  873.  *    None.
  874.  *
  875.  *----------------------------------------------------------------------
  876.  */
  877. unsigned short
  878. Fsrecov_Checksum(len, bufPtr)
  879.     register int len;        /* The number of bytes to checksum. */
  880.     Address bufPtr;        /* What to checksum. */
  881. {
  882.     register unsigned short *wordPtr = (unsigned short *) bufPtr;
  883.     register unsigned int sum = 0;
  884.  
  885.     
  886.     /*
  887.      * The basic algorithm 16-bit 1's complement addition is 
  888.      *  1) add the two unsigned 16-bit quantities, 
  889.      *  2) if there was a carry out of the high-order bit, 
  890.      *       it is added to the sum.
  891.      * To detect a carry out of the high-order bit, the sum is stored
  892.      * in a 32-bit word. As an optimization, we delay step 2 until
  893.      * all the words have been added together. At that point, the
  894.      * upper-half of the sum contains the sum of the carries from the
  895.      * additions. This value is then added to the lower half and if that
  896.      * operation causes a carry, then 1 is added to the sum.
  897.      *
  898.      * The optimization does place a limit on how many bytes can be
  899.      * summed without causing an overflow of the 32-bit sum. In the worst
  900.      * case, a maximum of 64K additions of 16-bit values can be added
  901.      * without overflow.
  902.      * 
  903.      * The summation is done in an unrolled loop. Once we have less than 
  904.      * 32 bytes to sum then it must be done in smaller loops.
  905.      */
  906.  
  907.     if (len != sizeof (Fsrecov_HandleState)) {
  908.     panic("Fsrecov_Checksum: object isn't an Fsrecov_HandleState.");
  909.     }
  910.     if (sizeof (Fsrecov_HandleState) != 52) {
  911.     panic("Fsrecov_Checksum: handle size has changed from 52 to %d.",
  912.         sizeof (Fsrecov_HandleState));
  913.     }
  914.     sum += *wordPtr++;
  915.     sum += *wordPtr++;
  916.     sum += *wordPtr++;
  917.     sum += *wordPtr++;
  918.     sum += *wordPtr++;
  919.  
  920.     sum += *wordPtr++;
  921.     sum += *wordPtr++;
  922.     sum += *wordPtr++;
  923.     sum += *wordPtr++;
  924.     sum += *wordPtr++;
  925.  
  926.     sum += *wordPtr++;
  927.     sum += *wordPtr++;
  928.     sum += *wordPtr++;
  929.     sum += *wordPtr++;
  930.     sum += *wordPtr++;
  931.  
  932.     sum += *wordPtr++;
  933.     sum += *wordPtr++;
  934.     sum += *wordPtr++;
  935.     sum += *wordPtr++;
  936.     sum += *wordPtr++;
  937.  
  938.     sum += *wordPtr++;
  939.     sum += *wordPtr++;
  940.     sum += *wordPtr++;
  941.     sum += *wordPtr++;
  942.     sum += *wordPtr++;
  943.  
  944.     sum += *wordPtr++;
  945.  
  946.     return((~sum & 0xffff));
  947. }
  948.  
  949.  
  950. /*
  951.  *----------------------------------------------------------------------
  952.  *
  953.  * Fsrecov_DirOpInit --
  954.  *
  955.  *    Initialize the logging of directory operations.
  956.  *
  957.  * Results:
  958.  *    None.
  959.  *
  960.  * Side effects:
  961.  *    Stuff gets initialized.
  962.  *
  963.  *----------------------------------------------------------------------
  964.  */
  965. void
  966. Fsrecov_DirOpInit()
  967. {
  968.     int            objectType;
  969.     int            i;
  970.     ReturnStatus    status;
  971.     Fsrecov_DirLogEntry    *entries;
  972.     int            entryArraySize;
  973.     Recov_ObjectID    *objectIDs;
  974.     int            objectIDArraySize;
  975.     int            numEntries = 0;
  976.     int            oldestTime = 0;
  977.     int            newestTime = 0;
  978.     int            newestEntry = 0;
  979.     int            logSeqNum;
  980.     int            compareTime;
  981.  
  982.     fsrecov_DirLog.nextLogSeqNum = 0;
  983.     fsrecov_DirLog.oldestEntry = -1;
  984.  
  985.     for (i = 0; i < FSRECOV_NUM_DIR_LOG_ENTRIES; i++) {
  986.     fsrecov_DirLogObjNums[i].objectNum = -1;
  987.     }
  988.  
  989.     if (!fsrecov_AlreadyInit) {
  990.     /* Set up the recovery box type number. */
  991.     status = Recov_InitType(sizeof (Fsrecov_DirLogEntry),
  992.         FSRECOV_NUM_DIR_LOG_ENTRIES, 0, &objectType,
  993.         (unsigned short (*)()) 1);
  994.     if (status != SUCCESS) {
  995.         panic("Fsrecov_DirOpInit: initialization of recovery type failed.");
  996.     }
  997.     if (objectType != FSRECOV_DIR_LOG_TYPE) {
  998.         panic("Fsrecov_DirOpInit: got wrong dir log recovery type.");
  999.     }
  1000.  
  1001.     return;
  1002.     }
  1003.  
  1004.     numEntries = Recov_NumObjects(FSRECOV_DIR_LOG_TYPE);
  1005.     if (numEntries <= 0) {
  1006.     return;
  1007.     }
  1008.     entryArraySize = numEntries * sizeof (Fsrecov_DirLogEntry);
  1009.     objectIDArraySize = numEntries * sizeof (Recov_ObjectID);
  1010.     entries = (Fsrecov_DirLogEntry *) malloc(entryArraySize);
  1011.     objectIDs = (Recov_ObjectID *) malloc(objectIDArraySize);
  1012.  
  1013.     status = Recov_ReturnObjects(FSRECOV_DIR_LOG_TYPE, &entryArraySize,
  1014.         (char *) entries, &objectIDArraySize, (char *) objectIDs,
  1015.         (int *) NIL, (char *) NIL);
  1016.     if (status != SUCCESS) {
  1017.     panic("Fsrecov_DirOpInit: couldn't get returned log entries.");
  1018.     }
  1019.     if ((entryArraySize / sizeof (Fsrecov_DirLogEntry)) != numEntries) {
  1020.     panic("Fsrecov_DirOpInit: something is wrong with # of log entries.");
  1021.     }
  1022.  
  1023.     for (i = 0; i < numEntries; i++) {
  1024.     logSeqNum = entries[i].logSeqNum;
  1025.     compareTime = entries[i].startTime;
  1026.     fsrecov_DirLogObjNums[logSeqNum].objectNum = objectIDs[i].objectNumber;
  1027.     /* Mark first with old startTime just for sorting purposes. */
  1028.     fsrecov_DirLogObjNums[logSeqNum].timeStamp = compareTime;
  1029.     if (fsrecov_DirLog.oldestEntry == -1) {
  1030.         fsrecov_DirLog.oldestEntry = logSeqNum;
  1031.         oldestTime = compareTime;
  1032.     }
  1033.     if ((compareTime < oldestTime) ||
  1034.         (compareTime == oldestTime &&
  1035.         logSeqNum < fsrecov_DirLog.oldestEntry)) {
  1036.         fsrecov_DirLog.oldestEntry = logSeqNum;
  1037.         oldestTime = compareTime;
  1038.     }
  1039.     if ((compareTime > newestTime) ||
  1040.         (compareTime == newestTime && logSeqNum > newestEntry)) {
  1041.         newestEntry = logSeqNum;
  1042.         newestTime = compareTime;
  1043.     }
  1044.     }
  1045.     /*
  1046.      * Now check if the oldest time and newest time were unique and whether
  1047.      * they wrapped around the end of the log.  'Cause if they did, we've
  1048.      * picked the wrong ones.
  1049.      */
  1050.     if (fsrecov_DirLog.oldestEntry == 0) {
  1051.     for (i = FSRECOV_NUM_DIR_LOG_ENTRIES - 1; i >= 0; i--) {
  1052.         if (fsrecov_DirLogObjNums[i].objectNum != -1 && 
  1053.             fsrecov_DirLogObjNums[i].timeStamp == oldestTime) {
  1054.         fsrecov_DirLog.oldestEntry = i;
  1055.         } else {
  1056.         break;
  1057.         }
  1058.     }
  1059.     }
  1060.     if (newestEntry == FSRECOV_NUM_DIR_LOG_ENTRIES - 1) {
  1061.     for (i = 0; i < FSRECOV_NUM_DIR_LOG_ENTRIES; i++) {
  1062.         if (fsrecov_DirLogObjNums[i].objectNum != -1 && 
  1063.             fsrecov_DirLogObjNums[i].timeStamp == newestTime) {
  1064.         newestEntry = i;
  1065.         } else {
  1066.         break;
  1067.         }
  1068.     }
  1069.     }
  1070.  
  1071.     fsrecov_DirLog.nextLogSeqNum = newestEntry + 1;
  1072.     if (fsrecov_DirLog.nextLogSeqNum >= FSRECOV_NUM_DIR_LOG_ENTRIES) {
  1073.     fsrecov_DirLog.nextLogSeqNum = 0;
  1074.     if (fsrecov_DirLogObjNums[0].objectNum != -1) {
  1075.         panic("Fsrecov_DirOpInit: log already filled on startup.");
  1076.     }
  1077.     }
  1078.  
  1079.     free((char *) entries);
  1080.     free((char *) objectIDs);
  1081.  
  1082.     /*
  1083.      * Now set time to current time, so we have a chance for these to
  1084.      * be written out before being removed from the log.
  1085.      */
  1086.     for (i = 0; i < FSRECOV_NUM_DIR_LOG_ENTRIES; i++) {
  1087.     if (fsrecov_DirLogObjNums[i].objectNum != -1) {
  1088.         fsrecov_DirLogObjNums[i].timeStamp = Fsutil_TimeInSeconds();
  1089.     }
  1090.     }
  1091.     return;
  1092. }
  1093.  
  1094.  
  1095. /*
  1096.  *----------------------------------------------------------------------
  1097.  *
  1098.  * Fsrecov_DirOpStart --
  1099.  *
  1100.  *    Note the start of a directory operation.
  1101.  *
  1102.  * Results:
  1103.  *    Client data identifying the log entry.
  1104.  *
  1105.  * Side effects:
  1106.  *    Log entry made in recovery box.
  1107.  *
  1108.  *----------------------------------------------------------------------
  1109.  */
  1110. ClientData
  1111. Fsrecov_DirOpStart(opFlags, dirHandlePtr, dirOffset, name, nameLen, fileNumber,
  1112.     type, fileDescPtr)
  1113.     int         opFlags;        /* Operation code and flags. See fsdm.h for
  1114.                                  * definitions. */
  1115.     Fsio_FileIOHandle *dirHandlePtr;    /* Handle of directory being operated
  1116.                                          * on. */
  1117.     int         dirOffset;      /* Byte offset into directory of the directory
  1118.                                  * entry containing operation. -1 if offset
  1119.                                  * is not known. */
  1120.     char        *name;          /* Name of object being operated on. */
  1121.     int         nameLen;        /* Length in characters of name. */
  1122.     int         fileNumber;     /* File number of object being operated on.*/
  1123.     int         type;           /* Type of the object being operated on. */
  1124.     Fsdm_FileDescriptor *fileDescPtr; /* FileDescriptor object being operated on
  1125.                                        * before operation starts. */
  1126. {
  1127.     Recov_ObjectID        objectID;
  1128.     register Fsdm_Domain        *domainPtr;
  1129.     Fsrecov_DirLogEntry        dirLogEntry;
  1130.     int                dirFileNumber = dirHandlePtr->hdr.fileID.minor;
  1131.     ReturnStatus        status;
  1132.  
  1133.     /*
  1134.      * Don't start adding entries until we've processed the ones already
  1135.      * in the box.  This will happen before we start accepting RPC's, so
  1136.      * we won't lose any directory op's that clients depend on.
  1137.      */
  1138.     if (!finishedInit) {
  1139.     return (ClientData) NIL;
  1140.     }
  1141.  
  1142.     domainPtr = Fsdm_DomainFetch(dirHandlePtr->hdr.fileID.major, FALSE);
  1143.     if (domainPtr == (Fsdm_Domain *)NIL) {
  1144.         return (ClientData) NIL;
  1145.     }
  1146.  
  1147.     opFlags |= FSRECOV_LOG_START_ENTRY;
  1148.  
  1149.  
  1150.     dirLogEntry.logSeqNum = fsrecov_DirLog.nextLogSeqNum; 
  1151.     fsrecov_DirLog.nextLogSeqNum++;
  1152.     /* Circular buffer. */
  1153.     if (fsrecov_DirLog.nextLogSeqNum >= FSRECOV_NUM_DIR_LOG_ENTRIES) {
  1154.     fsrecov_DirLog.nextLogSeqNum = 0;
  1155.     }
  1156.     /*
  1157.      * Log has wrapped on itself, flush out descriptor operations --
  1158.      * need call-backs that won't hurt work in progres.  We don't need to
  1159.      * wait for this here, necessarily, but next logging must wait till
  1160.      * this has finished.
  1161.      */
  1162.     if (fsrecov_DirLogObjNums[fsrecov_DirLog.nextLogSeqNum].objectNum != -1) {
  1163.     panic("Fsrecov_DirOpStart: Log has wrapped on itself.");
  1164.     }
  1165.  
  1166.     /* Fill in the rest of the entry. */
  1167.     dirLogEntry.opFlags = opFlags;
  1168.     dirLogEntry.dirFileNumber = dirFileNumber;
  1169.     dirLogEntry.dirOffset = dirOffset;
  1170.     dirLogEntry.linkCount = (fileDescPtr == (Fsdm_FileDescriptor *) NIL) ? 0 :
  1171.         fileDescPtr->numLinks;
  1172.     dirLogEntry.dirEntry.fileNumber = fileNumber;
  1173.     dirLogEntry.dirEntry.recordLength = Fslcl_DirRecLength(nameLen);
  1174.     dirLogEntry.dirEntry.nameLength = nameLen;
  1175.     dirLogEntry.startTime = Fsutil_TimeInSeconds();
  1176.     bcopy(name, dirLogEntry.dirEntry.fileName, nameLen);
  1177.  
  1178.     status = Recov_InsertObject(FSRECOV_DIR_LOG_TYPE,
  1179.         (ClientData) &dirLogEntry, -1, &objectID);
  1180.     if (status != SUCCESS) {
  1181.     panic("Fsrecov_DirOpStart: Couldn't insert new entry in log.");
  1182.     }
  1183.  
  1184.     fsrecov_DirLogObjNums[dirLogEntry.logSeqNum].objectNum =
  1185.         objectID.objectNumber;
  1186.     if (fsrecov_DirLog.oldestEntry < 0) {
  1187.     fsrecov_DirLog.oldestEntry = dirLogEntry.logSeqNum;
  1188.     }
  1189.  
  1190.     Fsdm_DomainRelease(dirHandlePtr->hdr.fileID.major);
  1191.  
  1192.     return (ClientData) dirLogEntry.logSeqNum;
  1193. }
  1194.  
  1195.  
  1196. /*
  1197.  *----------------------------------------------------------------------
  1198.  *
  1199.  * Fsrecov_DirOpEnd --
  1200.  *
  1201.  *    Note the end of a directory operation and its status.
  1202.  *
  1203.  * Results:
  1204.  *    None.
  1205.  *
  1206.  * Side effects:
  1207.  *    Log entry made in recovery box.
  1208.  *
  1209.  *----------------------------------------------------------------------
  1210.  */
  1211. void
  1212. Fsrecov_DirOpEnd(opFlags, dirHandlePtr, dirOffset, name, nameLen, fileNumber,
  1213.                 type, fileDescPtr, clientData, opStatus)
  1214.     int         opFlags;        /* Operation code and flags. See fsdm.h for
  1215.                                  * definitions. */
  1216.     Fsio_FileIOHandle *dirHandlePtr;    /* Handle of directory being operated
  1217.                                          * on. */
  1218.     int         dirOffset;      /* Byte offset into directory of the directory
  1219.                                  * entry containing operation. -1 if offset
  1220.                                  * is not known. */
  1221.     char        *name;          /* Name of object being operated on. */
  1222.     int         nameLen;        /* Length in characters of name. */
  1223.     int         fileNumber;     /* File number of objecting being operated on.*/
  1224.     int         type;           /* Type of the object being operated on. */
  1225.     Fsdm_FileDescriptor *fileDescPtr; /* FileDescriptor object being operated on
  1226.                                        * before operation starts. */
  1227.     ClientData  clientData;     /* ClientData as returned by DirOpStart. */
  1228.     ReturnStatus opStatus;    /* Return status of the operation, SUCCESS if
  1229.                                  * operation succeeded. FAILURE otherwise. */
  1230. {
  1231.     register    Fsdm_Domain    *domainPtr;
  1232.     Recov_ObjectID        objectID;
  1233.     ReturnStatus        status;
  1234.     Fsrecov_DirLogEntry        dirLogEntry;
  1235.  
  1236.     /*
  1237.      * Don't start adding entries until we've processed the ones already
  1238.      * in the box.  This will happen before we start accepting RPC's, so
  1239.      * we won't lose any directory op's that clients depend on.
  1240.      */
  1241.     if (!finishedInit) {
  1242.     return;
  1243.     }
  1244.  
  1245.     domainPtr = Fsdm_DomainFetch(dirHandlePtr->hdr.fileID.major, FALSE);
  1246.     if (domainPtr == (Fsdm_Domain *)NIL) {
  1247.         return;
  1248.     }
  1249.     opFlags |= FSRECOV_LOG_END_ENTRY;
  1250.  
  1251.     objectID.typeID = FSRECOV_DIR_LOG_TYPE;
  1252.     objectID.objectNumber = fsrecov_DirLogObjNums[(int) clientData].objectNum;
  1253.     if (objectID.objectNumber < 0) {
  1254.     panic("Fsrecov_DirOpEnd: entry not found.");
  1255.     }
  1256.     if (opStatus != SUCCESS) {
  1257.     /* Remove the log entry, since the operation failed. */
  1258.     status = Recov_DeleteObject(objectID);
  1259.     if (status != SUCCESS) {
  1260.         panic("Fsrecov_DirOpEnd: Couldn't delete entry.");
  1261.     }
  1262.     return;
  1263.     }
  1264.     status = Recov_ReturnObject((ClientData) &dirLogEntry, objectID, FALSE);
  1265.     if (status != SUCCESS) {
  1266.     panic("Fsrecov_DirOpEnd: Couldn't get entry.");
  1267.     }
  1268.     dirLogEntry.opFlags = opFlags;
  1269.     status = Recov_UpdateObject((ClientData) &dirLogEntry, objectID);
  1270.     if (status != SUCCESS) {
  1271.     panic("Fsrecov_DirOpEnd: Couldn't update entry.");
  1272.     }
  1273.  
  1274.     /*
  1275.      * FSRECOV_SAFE_SECONDS after this time stamp we can remove the entry
  1276.      * from log.
  1277.      */
  1278.     fsrecov_DirLogObjNums[(int) clientData].timeStamp = Fsutil_TimeInSeconds();
  1279.     Fsdm_DomainRelease(dirHandlePtr->hdr.fileID.major);
  1280.  
  1281.     return;
  1282. }
  1283.  
  1284.  
  1285. /*
  1286.  *----------------------------------------------------------------------
  1287.  *
  1288.  * Fsrecov_UpdateLog --
  1289.  *
  1290.  *    Remove entries in the directory operation log that are old enough
  1291.  *    to have been written safely.
  1292.  *
  1293.  * Results:
  1294.  *    None.
  1295.  *
  1296.  * Side effects:
  1297.  *    Log entries removed from recovery box.
  1298.  *
  1299.  *----------------------------------------------------------------------
  1300.  */
  1301. void
  1302. Fsrecov_UpdateLog(timeStamp)
  1303.     int        timeStamp;    /* If not NIL, use this as comparison time. */
  1304. {
  1305.     int        currentTime;
  1306.     int        seqNum;
  1307.     int        numEntries;
  1308.  
  1309.     if (!finishedInit) {
  1310.     return;
  1311.     }
  1312.  
  1313.     if (timeStamp == (int) NIL) {
  1314.     currentTime = Fsutil_TimeInSeconds();
  1315.     } else{
  1316.     currentTime = timeStamp;
  1317.     }
  1318.  
  1319.     seqNum = fsrecov_DirLog.oldestEntry;
  1320.     if (seqNum < 0) {
  1321.     return;
  1322.     }
  1323.     while (seqNum != fsrecov_DirLog.nextLogSeqNum &&
  1324.         Recov_NumObjects(FSRECOV_DIR_LOG_TYPE) > 0) {
  1325.         if (fsrecov_DirLogObjNums[seqNum].timeStamp >
  1326.         currentTime - FSRECOV_SAFE_SECONDS) {
  1327.         break;
  1328.     }
  1329.     Fsrecov_DirOpRemove((ClientData) seqNum);
  1330.     seqNum++;
  1331.     if (seqNum >= FSRECOV_NUM_DIR_LOG_ENTRIES) {
  1332.         seqNum = 0;
  1333.     }
  1334.     }
  1335.     numEntries = Recov_NumObjects(FSRECOV_DIR_LOG_TYPE);
  1336.     if (numEntries <= 0) {
  1337.     fsrecov_DirLog.oldestEntry = -1;
  1338.     } else {
  1339.     fsrecov_DirLog.oldestEntry = seqNum;
  1340.     }
  1341.     if (numEntries > 0 && fsrecov_DirLog.oldestEntry ==
  1342.         fsrecov_DirLog.nextLogSeqNum) {
  1343.     panic("Fsrecov_UpdateLog: something is wrong with the log.\n");
  1344.     }
  1345.  
  1346.     return;
  1347. }
  1348.  
  1349.  
  1350. /*
  1351.  *----------------------------------------------------------------------
  1352.  *
  1353.  * Fsrecov_DirOpRemove --
  1354.  *
  1355.  *    Remove an entry in the directory operation log.
  1356.  *
  1357.  * Results:
  1358.  *    None.
  1359.  *
  1360.  * Side effects:
  1361.  *    Log entry removed from recovery box.
  1362.  *
  1363.  *----------------------------------------------------------------------
  1364.  */
  1365. void
  1366. Fsrecov_DirOpRemove(clientData)
  1367.     ClientData        clientData;    /* Sequence number in log. */
  1368. {
  1369.     ReturnStatus    status;
  1370.     Recov_ObjectID    objectID;
  1371.  
  1372.     if (!finishedInit) {
  1373.     return;
  1374.     }
  1375.  
  1376.     objectID.typeID = FSRECOV_DIR_LOG_TYPE;
  1377.     objectID.objectNumber = fsrecov_DirLogObjNums[(int) clientData].objectNum;
  1378.     if (objectID.objectNumber < 0) {
  1379.     printf("Fsrecov_DirOpRemove: object already deleted.\n");
  1380.     return;
  1381.     }
  1382.  
  1383.     status = Recov_DeleteObject(objectID);
  1384.     if (status != SUCCESS) {
  1385.     panic("Fsrecov_DirOpRemove: couldn't delete log entry.");
  1386.     }
  1387.     fsrecov_DirLogObjNums[(int) clientData].objectNum = -1;
  1388.  
  1389.     return;
  1390. }
  1391.  
  1392. typedef    struct    FileIdent {
  1393.     int    major;
  1394.     int    minor;
  1395. } FileIdent;
  1396. typedef    struct    LogEntry {
  1397.     List_Links    links;
  1398.     Fsrecov_DirLogEntry    dirLogEntry;
  1399. } LogEntry;
  1400.  
  1401.  
  1402. /*
  1403.  *----------------------------------------------------------------------
  1404.  *
  1405.  * Fsrecov_ProcessLog --
  1406.  *
  1407.  *    Process the log entries, making sure the disk state reflects them.
  1408.  *
  1409.  * Results:
  1410.  *    None.
  1411.  *
  1412.  * Side effects:
  1413.  *    Disk state may be modified.
  1414.  *
  1415.  *----------------------------------------------------------------------
  1416.  */
  1417. void
  1418. Fsrecov_ProcessLog()
  1419. {
  1420.     FileIdent            fileIdent;
  1421.     LogEntry            *logEntryPtr;
  1422.     Fsrecov_DirLogEntry        dirLogEntry;
  1423.     Fsrecov_DirLogEntry        *dirLogEntryPtr;
  1424.     Hash_Table            descTable;
  1425.     Hash_Entry            *entryPtr = (Hash_Entry *) NIL;
  1426.     int                seqNum;
  1427.     LogEntry            *itemPtr;
  1428.     List_Links            *savePtr;
  1429.     List_Links            *otherItemPtr;
  1430.     Hash_Entry            *otherEntryPtr;
  1431.     ReturnStatus        status;
  1432.     Recov_ObjectID        objID;
  1433.     Fsdm_Domain            *domainPtr;
  1434.  
  1435.     seqNum = fsrecov_DirLog.oldestEntry;
  1436.     if (seqNum < 0) {
  1437.     finishedInit = TRUE;
  1438.     return;
  1439.     }
  1440.     Hash_Init(&descTable, 8, sizeof (FileIdent) / sizeof (int));
  1441.  
  1442.     /*
  1443.      * Try to put together a picture of what each mentioned directory
  1444.      * should contain in the way of names and desriptors.
  1445.      */
  1446.  
  1447.     objID.typeID = FSRECOV_DIR_LOG_TYPE;
  1448.     while (seqNum != fsrecov_DirLog.nextLogSeqNum) {
  1449.     /* Process the entry. */
  1450.     objID.objectNumber = fsrecov_DirLogObjNums[seqNum].objectNum;
  1451.     status = Recov_ReturnObject((ClientData) &dirLogEntry, objID, TRUE);
  1452.     if (status != SUCCESS) {
  1453.         panic("Fsrecov_ProcessLog: couldn't get entry.");
  1454.     }
  1455.     fileIdent.major = 0;        /* XXX Fix this. XXX */
  1456.     fileIdent.minor = dirLogEntry.dirFileNumber;
  1457.     entryPtr = Hash_Find(&descTable, (Address) &fileIdent);
  1458.     logEntryPtr = (LogEntry *) malloc(sizeof (LogEntry));
  1459.     List_InitElement((List_Links *) logEntryPtr);
  1460.     bcopy(&dirLogEntry, &(logEntryPtr->dirLogEntry),
  1461.         sizeof (dirLogEntry));
  1462.     if (entryPtr->value == (Address) NIL) {
  1463.         entryPtr->value = (Address) malloc(sizeof (List_Links));
  1464.         List_Init((List_Links *) (entryPtr->value));
  1465.         List_Insert((List_Links *) logEntryPtr,
  1466.             LIST_ATREAR((List_Links *) entryPtr->value));
  1467.         /*
  1468.          * Do I just want to remove the entry?  I can't go through
  1469.          * fast reboot anyway if it croaks here.
  1470.          */
  1471.         /* Reset time to now, so op will get written out before removed. */
  1472.         fsrecov_DirLogObjNums[seqNum].timeStamp = Fsutil_TimeInSeconds();
  1473.         seqNum++;
  1474.         if (seqNum >= FSRECOV_NUM_DIR_LOG_ENTRIES) {
  1475.         seqNum = 0;
  1476.         }
  1477.         continue;
  1478.     }
  1479.  
  1480.  
  1481.     /* Entries already exist for this parent directory. */
  1482.  
  1483.     LIST_FORALL((List_Links *) entryPtr->value, (List_Links *)itemPtr) {
  1484.         if ((itemPtr->dirLogEntry.dirEntry.nameLength ==
  1485.             dirLogEntry.dirEntry.nameLength) &&
  1486.             strncmp(itemPtr->dirLogEntry.dirEntry.fileName,
  1487.             dirLogEntry.dirEntry.fileName,
  1488.             dirLogEntry.dirEntry.nameLength) == 0) {
  1489.         int    op;
  1490.         /* Same filename. */
  1491.  
  1492.         switch (dirLogEntry.opFlags & FSDM_LOG_OP_MASK) {
  1493.         case FSDM_LOG_CREATE :
  1494.             op = (itemPtr->dirLogEntry.opFlags & FSDM_LOG_OP_MASK);
  1495.             if (op != FSDM_LOG_RENAME_DELETE && op != FSDM_LOG_UNLINK) {
  1496.             panic("Fsrecov_ProcessLog: incompatible log entry.");
  1497.             }
  1498.             break;
  1499.         case FSDM_LOG_LINK :
  1500.             break;
  1501.         case FSDM_LOG_RENAME_DELETE :
  1502.             break;
  1503.         case FSDM_LOG_RENAME_LINK :
  1504.             break;
  1505.         case FSDM_LOG_UNLINK :    /* Fall through. */
  1506.         case FSDM_LOG_RENAME_UNLINK :
  1507.             /* XXX What to do if it's still open? */
  1508.             /* What if it's a dir? */
  1509.             if (!(dirLogEntry.opFlags & FSDM_LOG_IS_DIRECTORY)) {
  1510.             break;
  1511.             }
  1512.             if (dirLogEntry.linkCount > 2) {
  1513.             break;
  1514.             }
  1515.             /*
  1516.              * It can be removed - find anything it's a
  1517.              * parent of and remove that from list.
  1518.              */
  1519.             fileIdent.major = 0;    /* XXX Fix this. XXX */
  1520.             fileIdent.minor = dirLogEntry.dirEntry.fileNumber;
  1521.             otherEntryPtr = Hash_LookOnly(&descTable,
  1522.                 (Address) &fileIdent);
  1523.             if (otherEntryPtr->value == (Address) NIL) {
  1524.             break;
  1525.             }
  1526.             /* Remove stuff. */
  1527.             while (!List_IsEmpty((List_Links *) otherEntryPtr->value)) {
  1528.             otherItemPtr = List_First((List_Links *)
  1529.                 otherEntryPtr->value);
  1530.             List_Remove(otherItemPtr);
  1531.             free((char *) otherItemPtr);
  1532.             }
  1533.             free(otherEntryPtr->value);
  1534.             Hash_Delete(&descTable, otherEntryPtr);
  1535.             break;
  1536.         default:
  1537.             panic("Fsrecov_ProcessLog: unknown operation.");
  1538.             break;
  1539.         }
  1540.         savePtr = (List_Links *) itemPtr;
  1541.         itemPtr = (LogEntry *) List_Prev((List_Links *) itemPtr);
  1542.         List_Remove(savePtr);
  1543.         }
  1544.     }
  1545.     List_Insert((List_Links *) logEntryPtr,
  1546.         LIST_ATREAR((List_Links *) entryPtr->value));
  1547.     /*
  1548.      * Do I just want to remove the entry?  I can't go through
  1549.      * fast reboot anyway if it croaks here.
  1550.      */
  1551.     /* Reset time to now, so op will get written out before removed. */
  1552.         fsrecov_DirLogObjNums[seqNum].timeStamp = Fsutil_TimeInSeconds();
  1553.     seqNum++;
  1554.     if (seqNum >= FSRECOV_NUM_DIR_LOG_ENTRIES) {
  1555.         seqNum = 0;
  1556.     }
  1557.     }
  1558.  
  1559.     domainPtr = Fsdm_DomainFetch(0 /* XXX Fix this. XXX */, FALSE /* TRUE? */);
  1560.  
  1561.     /* Now check disk to see that it matches state we've accumulated. */
  1562.  
  1563.     if (logProcessDebug) {    /* Just print what the state is. */
  1564.     Hash_Search        hashSearch;
  1565.     Hash_Entry        *entryPtr;
  1566.     Fsio_FileIOHandle    *parentHandlePtr;
  1567.     Fs_FileID        fileID;
  1568.  
  1569.     Hash_StartSearch(&hashSearch);
  1570.     printf("Fsrecov_ProcessLog: Printing state:\n");
  1571.  
  1572.     for (entryPtr = Hash_Next(&descTable, &hashSearch);
  1573.         entryPtr != (Hash_Entry *) NIL;
  1574.         entryPtr = Hash_Next(&descTable, &hashSearch)) {
  1575.         char    buf[256];
  1576.  
  1577.         fileID.type = 1;
  1578.         fileID.serverID = rpc_SpriteID;
  1579.         fileID.major = 0;    /* XXX Fix this! XXX */
  1580.         fileID.minor = entryPtr->key.words[1];
  1581.         parentHandlePtr = (Fsio_FileIOHandle *) Fsutil_HandleFetch(&fileID);
  1582.         if (parentHandlePtr == (Fsio_FileIOHandle *) NIL) {
  1583.         status = Fsio_LocalFileHandleInit(&fileID,
  1584.             dirLogEntry.dirEntry.fileName,
  1585.             (Fsdm_FileDescriptor *) NIL, FALSE, &parentHandlePtr);
  1586.         if (status != SUCCESS) {
  1587.             panic("Fsrecov_ProcessLog: couldn't get handle for dir.");
  1588.         }
  1589.         }
  1590.         LIST_FORALL((List_Links *) entryPtr->value,
  1591.             (List_Links *) logEntryPtr) {
  1592.         dirLogEntryPtr = &(logEntryPtr->dirLogEntry);
  1593.         strncpy(buf, dirLogEntryPtr->dirEntry.fileName,
  1594.             dirLogEntryPtr->dirEntry.nameLength);
  1595.         buf[dirLogEntryPtr->dirEntry.nameLength] = '\0';
  1596.         }
  1597.         Fslcl_CheckDirLog(parentHandlePtr, (List_Links *) entryPtr->value);
  1598.         Fsutil_HandleUnlock(parentHandlePtr);
  1599.     }
  1600.         
  1601.     finishedInit = TRUE;
  1602.     return;
  1603.     }
  1604.  
  1605.     finishedInit = TRUE;
  1606.     return;
  1607. }
  1608.  
  1609.  
  1610. /*
  1611.  *----------------------------------------------------------------------
  1612.  *
  1613.  * LogOpString --
  1614.  *
  1615.  *    Return a string representing the operation logged.
  1616.  *
  1617.  * Results:
  1618.  *    The string.
  1619.  *
  1620.  * Side effects:
  1621.  *    None.
  1622.  *
  1623.  *----------------------------------------------------------------------
  1624.  */
  1625. char *
  1626. LogOpString(op)
  1627.     int        op;
  1628. {
  1629.     static    char    returnString[256];
  1630.  
  1631.     switch (op & FSDM_LOG_OP_MASK) {
  1632.     case FSDM_LOG_CREATE :
  1633.     strcpy(returnString, "Create ");
  1634.     break;
  1635.     case FSDM_LOG_UNLINK :
  1636.     strcpy(returnString, "Unlink ");
  1637.     break;
  1638.     case FSDM_LOG_LINK :
  1639.     strcpy(returnString, "Link ");
  1640.     break;
  1641.     case FSDM_LOG_RENAME_DELETE :
  1642.     strcpy(returnString, "Rename delete ");
  1643.     break;
  1644.     case FSDM_LOG_RENAME_LINK :
  1645.     strcpy(returnString, "Rename link ");
  1646.     break;
  1647.     case FSDM_LOG_RENAME_UNLINK :
  1648.     strcpy(returnString, "Rename unlink ");
  1649.     break;
  1650.     default: 
  1651.     strcpy(returnString, "Unknown ");
  1652.     break;
  1653.     }
  1654.     
  1655.     if (op & FSRECOV_LOG_START_ENTRY) {
  1656.     strcat(returnString, "START ");
  1657.     }
  1658.     if (op & FSRECOV_LOG_END_ENTRY) {
  1659.     strcat(returnString, "END ");
  1660.     }
  1661.     if (op & FSDM_LOG_STILL_OPEN) {
  1662.     strcat(returnString, "OPEN ");
  1663.     }
  1664.     if (op & FSDM_LOG_IS_DIRECTORY) {
  1665.     strcat(returnString, "DIRECTORY ");
  1666.     }
  1667.  
  1668.     return returnString;
  1669. }
  1670.  
  1671. /*
  1672.  *----------------------------------------------------------------------
  1673.  *
  1674.  * Fsrecov_GetComponent --
  1675.  *
  1676.  *    Return file name and its length from a dir log entry.
  1677.  *
  1678.  * Results:
  1679.  *    Name and length in parameters.
  1680.  *
  1681.  * Side effects:
  1682.  *    None.
  1683.  *
  1684.  *----------------------------------------------------------------------
  1685.  */
  1686. void
  1687. Fsrecov_GetComponent(itemPtr, componentPtr, lengthPtr)
  1688.     List_Links    *itemPtr;
  1689.     char    **componentPtr;
  1690.     int        *lengthPtr;
  1691. {
  1692.     LogEntry    *logEntryPtr;
  1693.  
  1694.     logEntryPtr = (LogEntry *) itemPtr;
  1695.     *componentPtr = logEntryPtr->dirLogEntry.dirEntry.fileName;
  1696.     *lengthPtr = logEntryPtr->dirLogEntry.dirEntry.nameLength;
  1697.  
  1698.     return;
  1699. }
  1700.  
  1701. /*
  1702.  *----------------------------------------------------------------------
  1703.  *
  1704.  * Fsrecov_TestCmd --
  1705.  *
  1706.  *    Test timings of fsrecov and recov stuff.  This is called directly
  1707.  *    by Sys_StatsStub and therefore has the same interface.
  1708.  *
  1709.  * Results:
  1710.  *    Failure if test fails.
  1711.  *
  1712.  * Side effects:
  1713.  *    None.
  1714.  *
  1715.  *----------------------------------------------------------------------
  1716.  */
  1717. ReturnStatus
  1718. Fsrecov_TestCmd(option, argPtr)
  1719.     int        option;
  1720.     Address    argPtr;
  1721. {
  1722.     ReturnStatus    status = SUCCESS;
  1723.  
  1724.     switch (option) {
  1725.     case RECOV_PRINT_REBOOT_TIMES: {
  1726.     Time    answer;
  1727.     int    sum;
  1728.     
  1729.     printf("Total objects recovered: %d\n", fsrecov_RebuildNumObjs);
  1730.     if (fsrecov_RebuildNumObjs <= 0) {
  1731.         break;
  1732.     }
  1733.     Time_Subtract(fsrecov_EndRebuild, fsrecov_StartRebuild,
  1734.         &answer);
  1735.     printf("Time to do rebuild: %d seconds, %d microseconds\n",
  1736.         answer.seconds, answer.microseconds);
  1737.     sum = (answer.seconds * 1000000) + answer.microseconds;
  1738.     sum /= fsrecov_RebuildNumObjs;
  1739.     printf("Rebuild time per obj: %d microseconds \n", sum);
  1740.     Time_Subtract(fsrecov_ReturnedObjs, fsrecov_StartRebuild,
  1741.         &answer);
  1742.     printf("Time to return objs: %d seconds, %d microseconds\n",
  1743.         answer.seconds, answer.microseconds);
  1744.     Time_Subtract(fsrecov_BuiltHashTable, fsrecov_ReturnedObjs,
  1745.         &answer);
  1746.     printf("Time to build hashtable: %d seconds, %d microseconds\n",
  1747.         answer.seconds, answer.microseconds);
  1748.     Time_Subtract(fsrecov_BuiltIOHandles, fsrecov_BuiltHashTable,
  1749.         &answer);
  1750.     printf("Time to do IOHandles: %d seconds, %d microseconds\n",
  1751.         answer.seconds, answer.microseconds);
  1752.     Time_Subtract(fsrecov_EndRebuild, fsrecov_BuiltIOHandles,
  1753.         &answer);
  1754.     printf("Time to do streams: %d seconds, %d microseconds\n",
  1755.         answer.seconds, answer.microseconds);
  1756.  
  1757.     break;
  1758.     }
  1759.     case RECOV_TEST_ADD_DELETE: {
  1760.     Fsio_FileIOHandle    handle;
  1761.     Fs_HandleHeader        *hdrPtr = (Fs_HandleHeader *) &handle;
  1762.     struct Fsdm_FileDescriptor desc;
  1763.     int        q;
  1764.     Time         time1;
  1765.     Time         time2;
  1766.     Time         answer;
  1767.     Recov_ObjectID    objID;
  1768.     int        numHandles;
  1769.     int        iterations;
  1770.     int        sum;
  1771.     Recov_ObjectID    *objArrayPtr;
  1772.     int        i;
  1773.  
  1774.     if (argPtr == (Address) NIL || argPtr == (Address) 0) {
  1775.         numHandles = 1;
  1776.         iterations = 1000;
  1777.     } else {
  1778.         numHandles = ((Recov_Timings *) argPtr)->numHandles;
  1779.         iterations = ((Recov_Timings *) argPtr)->iterations;
  1780.     }
  1781.     hdrPtr->fileID.type = FSIO_LCL_FILE_STREAM;
  1782.     hdrPtr->fileID.serverID = 53;
  1783.     hdrPtr->fileID.major = 99;
  1784.     hdrPtr->fileID.minor = 99;
  1785.     handle.descPtr = &desc;
  1786.  
  1787.     Timer_GetTimeOfDay(&time1, (int *) NIL, (Boolean *) NIL);
  1788.  
  1789.     for (q = 0; q < iterations; q++) {
  1790.         for (i = 0; i < numHandles; i++) {
  1791.         hdrPtr->fileID.minor = 99 + i;
  1792.         if (Fsrecov_AddHandle(hdrPtr, (Fs_FileID *) NIL,
  1793.             99, 0, 1, TRUE) != SUCCESS) {
  1794.             printf("BAD FS_ADD_HANDLE.\n");
  1795.             status = FAILURE;
  1796.             break;
  1797.         }
  1798.         }
  1799.         if (status != SUCCESS) {
  1800.         break;
  1801.         }
  1802.         for (i = 0; i < numHandles; i++) {
  1803.         hdrPtr->fileID.minor = 99 + i;
  1804.         if (Fsrecov_DeleteHandle(hdrPtr, 99,
  1805.             FS_LAST_DIRTY_BLOCK) != SUCCESS) {
  1806.             printf("BAD FS_DELETE_HANDLE.\n");
  1807.             status = FAILURE;
  1808.             break;
  1809.         }
  1810.         }
  1811.         if (status != SUCCESS) {
  1812.         break;
  1813.         }
  1814.     }
  1815.     if (status != SUCCESS) {
  1816.         break;
  1817.     }
  1818.     Timer_GetTimeOfDay(&time2, (int *) NIL, (Boolean *) NIL);
  1819.     Time_Subtract(time2, time1, &answer);
  1820.     sum = (answer.seconds * 1000000) + answer.microseconds;
  1821.     sum /= iterations;
  1822.     sum /= numHandles;
  1823.     printf(
  1824.     "FS ANSWER, %d iterations, %d handles: %d seconds, %d usecs\n",
  1825.         iterations, numHandles, answer.seconds,
  1826.         answer.microseconds);
  1827.     printf("FS ANSWER per iteration per handle: %d microseconds\n",
  1828.         sum);
  1829.     
  1830.  
  1831.     objArrayPtr = (Recov_ObjectID *)
  1832.         malloc(numHandles * sizeof (Recov_ObjectID));
  1833.     Timer_GetTimeOfDay(&time1, (int *) NIL, (Boolean *) NIL);
  1834.     for (q = 0; q < iterations; q++) {
  1835.         for (i = 0; i < numHandles; i++) {
  1836.         hdrPtr->fileID.minor = 99 + i;
  1837.         if (Recov_InsertObject(0, (ClientData) hdrPtr,
  1838.             -1, &objID) != SUCCESS) {
  1839.             printf("BAD RECOV ADD\n");
  1840.             status = FAILURE;
  1841.             break;
  1842.         }
  1843.         objArrayPtr[i] = objID;
  1844.         }
  1845.         if (status != SUCCESS) {
  1846.         break;
  1847.         }
  1848.         for (i = 0; i < numHandles; i++) {
  1849.         hdrPtr->fileID.minor = 99 + i;
  1850.         if (Recov_DeleteObject(objArrayPtr[i]) != SUCCESS) {
  1851.             printf("BAD RECOV DELETE\n");
  1852.             status = FAILURE;
  1853.             break;
  1854.         }
  1855.         }
  1856.         if (status != SUCCESS) {
  1857.         break;
  1858.         }
  1859.     }
  1860.     if (status != SUCCESS) {
  1861.         break;
  1862.     }
  1863.     Timer_GetTimeOfDay(&time2, (int *) NIL, (Boolean *) NIL);
  1864.     Time_Subtract(time2, time1, &answer);
  1865.     printf(
  1866.     "RECOV ANSWER, %d iterations, %d handles: %d seconds, %d usecs\n",
  1867.         iterations, numHandles, answer.seconds,
  1868.         answer.microseconds);
  1869.     sum = (answer.seconds * 1000000) + answer.microseconds;
  1870.     sum /= iterations;
  1871.     sum /= numHandles;
  1872.     printf(
  1873.         "RECOV_ANSWER per iteration per handle: %d microseconds\n",
  1874.         sum);
  1875.  
  1876.     break;
  1877.     }
  1878.     case RECOV_TEST_ADD: {
  1879.     Fsio_FileIOHandle    handle;
  1880.     Fs_HandleHeader        *hdrPtr = (Fs_HandleHeader *) &handle;
  1881.     struct Fsdm_FileDescriptor desc;
  1882.     int        q;
  1883.     Time         time1;
  1884.     Time         time2;
  1885.     Time         answer;
  1886.     Recov_ObjectID    objID;
  1887.     int        numHandles;
  1888.     int        iterations;
  1889.     int        sum;
  1890.     Recov_ObjectID    *objArrayPtr;
  1891.     int        i;
  1892.  
  1893.     if (argPtr == (Address) NIL || argPtr == (Address) 0) {
  1894.         numHandles = 1;
  1895.         iterations = 1000;
  1896.     } else {
  1897.         numHandles = ((Recov_Timings *) argPtr)->numHandles;
  1898.         iterations = ((Recov_Timings *) argPtr)->iterations;
  1899.     }
  1900.     hdrPtr->fileID.type = FSIO_LCL_FILE_STREAM;
  1901.     hdrPtr->fileID.serverID = 53;
  1902.     hdrPtr->fileID.major = 99;
  1903.     hdrPtr->fileID.minor = 99;
  1904.     handle.descPtr = &desc;
  1905.  
  1906.  
  1907.     sum = 0;
  1908.     for (q = 0; q < iterations; q++) {
  1909.         Timer_GetTimeOfDay(&time1, (int *) NIL, (Boolean *) NIL);
  1910.         for (i = 0; i < numHandles; i++) {
  1911.         hdrPtr->fileID.minor = 99 + i;
  1912.         if (Fsrecov_AddHandle(hdrPtr, (Fs_FileID *) NIL,
  1913.             99, 0, 1, TRUE) != SUCCESS) {
  1914.             printf("BAD FS_ADD_HANDLE.\n");
  1915.             status = FAILURE;
  1916.             break;
  1917.         }
  1918.         }
  1919.         if (status != SUCCESS) {
  1920.         break;
  1921.         }
  1922.         Timer_GetTimeOfDay(&time2, (int *) NIL, (Boolean *) NIL);
  1923.         for (i = 0; i < numHandles; i++) {
  1924.         hdrPtr->fileID.minor = 99 + i;
  1925.         if (Fsrecov_DeleteHandle(hdrPtr, 99,
  1926.             FS_LAST_DIRTY_BLOCK) != SUCCESS) {
  1927.             printf("BAD FS_DELETE_HANDLE.\n");
  1928.             status = FAILURE;
  1929.             break;
  1930.         }
  1931.         }
  1932.         if (status != SUCCESS) {
  1933.         break;
  1934.         }
  1935.         Time_Subtract(time2, time1, &answer);
  1936.         sum += (answer.seconds * 1000000) + answer.microseconds;
  1937.     }
  1938.     if (status != SUCCESS) {
  1939.         break;
  1940.     }
  1941.     printf(
  1942.     "FS ANSWER, %d iterations, %d handles\n", iterations,
  1943.         numHandles);
  1944.     sum /= iterations;
  1945.     sum /= numHandles;
  1946.     printf("FS ANSWER per iteration per handle: %d microseconds\n",
  1947.         sum);
  1948.     
  1949.  
  1950.     objArrayPtr = (Recov_ObjectID *)
  1951.         malloc(numHandles * sizeof (Recov_ObjectID));
  1952.     sum = 0;
  1953.     for (q = 0; q < iterations; q++) {
  1954.         Timer_GetTimeOfDay(&time1, (int *) NIL, (Boolean *) NIL);
  1955.         for (i = 0; i < numHandles; i++) {
  1956.         hdrPtr->fileID.minor = 99 + i;
  1957.         if (Recov_InsertObject(0, (ClientData) hdrPtr,
  1958.             -1, &objID) != SUCCESS) {
  1959.             printf("BAD RECOV ADD\n");
  1960.             status = FAILURE;
  1961.             break;
  1962.         }
  1963.         objArrayPtr[i] = objID;
  1964.         }
  1965.         if (status != SUCCESS) {
  1966.         break;
  1967.         }
  1968.         Timer_GetTimeOfDay(&time2, (int *) NIL, (Boolean *) NIL);
  1969.         for (i = 0; i < numHandles; i++) {
  1970.         hdrPtr->fileID.minor = 99 + i;
  1971.         if (Recov_DeleteObject(objArrayPtr[i]) != SUCCESS) {
  1972.             printf("BAD RECOV DELETE\n");
  1973.             status = FAILURE;
  1974.             break;
  1975.         }
  1976.         }
  1977.         if (status != SUCCESS) {
  1978.         break;
  1979.         }
  1980.         Time_Subtract(time2, time1, &answer);
  1981.         sum += (answer.seconds * 1000000) + answer.microseconds;
  1982.     }
  1983.     if (status != SUCCESS) {
  1984.         break;
  1985.     }
  1986.     printf( "RECOV ANSWER, %d iterations, %d handles\n", iterations,
  1987.         numHandles);
  1988.     sum /= iterations;
  1989.     sum /= numHandles;
  1990.     printf(
  1991.         "RECOV_ANSWER per iteration per handle: %d microseconds\n",
  1992.         sum);
  1993.  
  1994.     break;
  1995.     }
  1996.     default:
  1997.     printf("Fsrecov_TestCmd: Invalid argument.\n");
  1998.     break;
  1999.     }
  2000.     return status;
  2001. }
  2002. #undef CHECK
  2003.